﻿/*
Plugin=DM_Copy_Files
Name1=移动文件到指定的文件夹中，左键移动，右键复制
Command1=DM_Copy_Files
Author=Run,Kawvin
Version=1.3版本
更新：
可以一条菜单即添加N个目录位置，无需使用多个菜单
用户即可自定义菜单名，（菜单名在前，目录路径在后，中间用“|”隔开即可）
例子：
复制或移入新建文件夹|C:\Users\guo\Desktop\新建文件夹
复制或移入D:\1234|D:\1234
*/

DM_Copy_Files(aParam){    ; 此Plugin执行的command为Test，代表执行Test函数,函数请预留一个aParam，用于QuickZ传递参数过来。
	icon:=A_ScriptDir . "\User\Icons\add.ico"
    Menu_copy_files := MenuZ_GetSibling() ; 获取一个菜单对象，不是子菜单，是同级菜单
	;Menu_copy_files := MenuZ_GetSub() ; 获取一个子菜单对象
	if !strlen(aParam)
		Menu_copy_files.Add({name:"左键移动，右键复制，中键打开目录，按住左Ctrl打开子目录,",icon: icon,uid:{Handle:"DM_copy_files_Handle",Data:"My_示例xxxxx"}}) 
	loop,parse, aParam,`n,`r
	{
		MenuString:=trim(A_LoopField)
		if InStr(MenuString, "|") 
		{						;方便用户自定义菜单名
			StringSplit, name, MenuString, `|
			name=%name1%
			destiny=%name2%
			Menu_copy_files.Add({name:name,icon: icon,uid:{Handle:"DM_copy_files_Handle",Data:destiny}}) ; Handle的值为点击菜单后执行的功能
		}
	}
    return Menu_copy_files  ; 必须返回子菜单对象
}

DM_copy_files_Handle(aMsg, aObj)
{
	DirectionDir:=aObj.Uid.Data
	if(DirectionDir="")
		return
	if (DirectionDir="")	or (!FileExist(DirectionDir))		;没有目标文件夹，则选择文件夹
	{
		FileSelectFolder, Select_Folder, , 3, 请选择目标目录
		if ErrorLevel
			Return
		if (Select_Folder="")
			return
		DirectionDir:=Select_Folder
	}
    If (aMsg = "OnRun")
		MySub_ActionToDirection(DirectionDir,"移动")		;移动文件
	else If (aMsg = "OnRButton")			
		MySub_ActionToDirection(DirectionDir,"复制")		;复制文件
	else If (aMsg = "onmbutton")
		MySub_ActionToDirection(DirectionDir,"打开目录")		;打开目标目录
}

MySub_ActionToDirection(DirectionDir,aMsg:="移动")
{
	MySel:=QZData("Files")
	if (!strlen(MySel))	;如数据，则退出
		return
	if (GetKeyState2("lCtrl","P")="D")		    ;按住lwin，弹出目标目录子文件夹的子文件夹生成的菜单    按下时是 D 而弹起时是 U
	{	
		GetKeyState, f_OpenFavCState, lCtrl   ;检测ctrl的按键状态
		if f_OpenFavCState = D   ;如果状态为D，说明lwin是按下的状态，所点击的item的属性是D的话说明是文件夹，此时打开他的子文件夹菜单
		{
			Create_sub_Menu(DirectionDir,aMsg)		;创建目标目录下子文件夹菜单
			Menu, sub_FolderMenu, UseErrorLevel
			Menu, sub_FolderMenu, Show
			if ErrorLevel   ; 不能创建菜单，返回
			{
				Menu, %Menu%, UseErrorLevel, OFF
				MsgBox 该文件没有子文件夹MsgBox, 64, 移动复制文件到指定文件夹, 该文件夹下没有子文件夹, 1
				return
			} else  { ; 显示菜单并返回
				Menu, %Menu%, UseErrorLevel, OFF
				return
			}
		}
		return
	}
	else
		MySub_FilesAction(DirectionDir, aMsg)  ;不按win键移动
}

Create_sub_Menu(TMPath,aMsg)   		 ;创建子菜单
{
	Menu, sub_FolderMenu, Add
	Menu, sub_FolderMenu, Delete   ; 删除旧菜单
	if RegExMatch(TMPath,":\\$")		;如果是盘符
		file_name:=TMPath
	else
	{
		TMPath:=RegExReplace(TMPath,"\\$","",all)		;去掉最后一个\
		SplitPath, TMPath, file_name
	}
	ParentItem=%file_name%`=%TMPath%   			;创建父菜单，格式是：文件名=文件全路径
	Create_Menu("sub_FolderMenu", ParentItem, "1", 1,aMsg)
	loop, %TMPath%\*, 2  								 ; 2代表只获取文件夹
		ItemList = %A_LoopFileName%`=%A_LoopFileFullPath% `n %ItemList%   ;A_LoopFileName为找到的文件名，A_LoopFileFullPath为找到的文件全路径
	Sort, ItemList  		 ; 排序并创建菜单
	Clipboard:=ItemList
	Menu, sub_FolderMenu, Add	
	loop, Parse, ItemList, `n
	{
		if (A_LoopField="")
			continue
		Create_Menu("sub_FolderMenu", A_LoopField, "1", A_Index+2,aMsg)
	}
	if (ItemList ="") 	 ; 没有子文件夹，删除菜单
		Menu, sub_FolderMenu, Delete
	return
}

Create_Menu(ThisMenu, ThisMenuItem, ThisMenuItemFirstChar, Pos,aMsg)  ;函数的参数分别为菜单名，菜单item，菜单item的第一个下划线
{
	Local ThisMenuItem0
	Local ThisMenuItem1
	Local ThisMenuItem2
	Local bMsg:=aMsg
	{
		Sleep 10
		StringSplit, ThisMenuItem, ThisMenuItem, `=  ;使用指定的分隔符（这儿是=）把一个字符串分解成多个子字符串并保存到数组中。
		ThisMenuItem1 = %ThisMenuItem1%   ; Trim leading and trailing Spaces.
		ThisMenuItem2 = %ThisMenuItem2%   ; Trim leading and trailing Spaces.
		StringReplace,ThisMenuItem1,ThisMenuItem1,+,`t,all
		Transform, i_%ThisMenu%_%Pos%_Path, deref, %ThisMenuItem2%  ;执行各种数学计算、按位运算以及类似 ASCII/Unicode 转换的任务。
		Transform, i_%ThisMenu%_%Pos%_Action, deref, %aMsg%  ;执行各种数学计算、按位运算以及类似 ASCII/Unicode 转换的任务。
		Menu, %ThisMenu%, Add, %ThisMenuItem1%, OpenFavorite
		if InStr(FileExist(ThisMenuItem2), "D")				;创建图标
		{
			RegExMatch(ThisMenuItem2, "\\+([^\\]+?)\\*$", m)
			if (m1="Desktop")
				Menu, %ThisMenu%, Icon, %ThisMenuItem1%,  Shell32.dll, 35
			else
				Menu, %ThisMenu%, Icon, %ThisMenuItem1%,  Shell32.dll, 5
		}
		%ThisMenu%ItemPos++
		return
	}
	OpenFavorite:              ;点击菜单时执行的功能
		Local bMsg
		StringTrimLeft, Path, i_%A_ThisMenu%_%A_ThisMenuItemPos%_Path, 0  ;如果Count小于或等于零, 那么 OutputVar 会被置为与 InputVar 相同，相当于把Input的值输出来了，也就是说MsgBox % i_%A_ThisMenu%_%A_ThisMenuItemPos%_Path的值等于path
		StringTrimLeft, Action, i_%A_ThisMenu%_%A_ThisMenuItemPos%_Action, 0
		GetKeyState, f_OpenFavCState, lCtrl   ;检测lwin的按键状态
		if f_OpenFavCState = D   ;如果状态为D，说明lwin是按下的状态，继续loop子文件夹，此时打开他的子文件夹菜单
		{
			MySub_ActionToDirection(Path,Action)
		}
		else          ;如果lwin没有按下，则移入当前item所指的路径当中
		{
			MySub_FilesAction(Path,Action)			;如果是文件夹的子文件夹归类，则默认启用复制动作，后面修改
		}
	return
}


GetKeyState2(WhichKey , Mode = "")
{
	_v:= ""
	GetKeyState, _v, %WhichKey%, %Mode%
	return _v
}

MySub_FilesAction(DirectionDir,aMsg:="移动")
{
	MySel:=QZData("Files")
	if (!strlen(MySel))	;如数据，则退出
		return
	if (aMsg="打开目录")
	{
		Run, % "explorer.exe /open,"DirectionDir
		sleep,200
		send,{Esc}{Esc}{Esc}
	}
	if(aMsg="移动")
	{
		MsgBox, 36, [动态菜单】文件移动确认, 确认移动以下文件到：`n-----------------------------------------------`n【目标目录】：%DirectionDir%`n【文件列表】：`n%MySel%
		IfMsgBox no
			return
		loop,Parse,MySel,`n,`r
		{
			if  InStr(FileExist(A_LoopField), "D"){
				SplitPath, A_LoopField, name2, dir, ext, name_no_ext, Drive
				FileMoveDir, %A_LoopField%, %DirectionDir%\%name2%  ; 移动到新驱动器。
			}
			FileMove,%A_LoopField%,%DirectionDir%    ;\%CandySel_FileNamenoExt%.%CandySel_FileExtension%
		}
	}
	if(aMsg="复制")
	{
		MsgBox, 36, [动态菜单】文件复制确认, 确认复制以下文件到：`n-----------------------------------------------`n【目标目录】：%DirectionDir%`n【文件列表】：`n%MySel%
		IfMsgBox no
			return
		loop,Parse,MySel,`n,`r
		{
			if  InStr(FileExist(A_LoopField), "D"){
				SplitPath, A_LoopField, name2, dir, ext, name_no_ext, Drive
				FileCopyDir, %A_LoopField%, %DirectionDir%\%name2%  ; 移动到新驱动器。
			}
			FileCopy,%A_LoopField%,%DirectionDir%    ;\%CandySel_FileNamenoExt%.%CandySel_FileExtension%
		}
		sleep,200
		send,{Esc}
	}
}